use std::time::Duration;
use std::thread;
mod game;
mod state;
mod algo_uct;
mod protocol;

use game::{Piece,Loc};
use state::{State,MessageAE,MessageEA};
use algo_uct::UCT;

const ENGINE_NAME:&str = "lianstar-rs-230208";
const THINK_RESEVER_TIME:Duration = Duration::from_millis(500);

fn make_think_thread(shared:State) -> thread::JoinHandle<()> {
    const POLL_SPAC_TIME:Duration = Duration::from_millis(100);
    thread::spawn(move || {
        let mut uct = UCT::new(shared.clone());
        let mut shared = shared.clone();
        loop {
            let msg = shared.poll_message_ea();
            match msg {
                MessageEA::Get(me_piece, time_usable) => {
                    shared.take_message_ea();
                    if me_piece == game::P_EMPTY {
                        shared.send_message_ae(MessageAE::MovePass)
                    } else {
                        let result = uct.step(me_piece, time_usable - THINK_RESEVER_TIME);
                        shared.send_message_ae(match result {
                            Some(loc) => {MessageAE::MoveLoc(loc)}
                            None => {MessageAE::MovePass}
                        })
                    }
                }
                MessageEA::Stop => {
                    shared.take_message_ea();
                    return
                }
                _ => {}
            }
            thread::sleep(POLL_SPAC_TIME);
        }
    })
}

struct Engine {
    shared: State,
    think_thread: thread::JoinHandle<()>,
    last_get_id: String,
}
impl Engine {
    fn new() -> Engine {
        let shared = State::new();
        Engine {
            shared: shared.clone(),
            think_thread: make_think_thread(shared),
            last_get_id: String::new(),
        }
    }

    fn raii(self) {
        if ! self.think_thread.is_finished() {
            self.think_thread.join().unwrap();
        }
    }

    fn init(&mut self) -> bool {
        true
    }
}

impl protocol::Receiver for Engine {
    fn get(&mut self,  me_piece:Piece, time_usable:Duration, id:&str) {
        self.last_get_id = String::from(id);
        self.shared.send_message_ea(MessageEA::Get(me_piece, time_usable))
    }
    fn set_board(&mut self, black_locs:&[Loc], white_locs:&[Loc], lastmove_loc:Option<Loc>) {
        let mut board = game::board_make_empty();
        for loc in black_locs {
            board[*loc] = game::P_BLACK
        }
        for loc in white_locs {
            board[*loc] = game::P_WHITE
        }
        self.shared.new_board_set(&board);
        self.shared.board_lastmove_loc_set(match lastmove_loc {
            Some(loc) => {loc}
            None => {Loc::MAX}
        })
    }
    fn set_rule_forbidden(&mut self, use_forbidden:bool) {
    }
    fn set_rule_canswaps(&mut self, insteps:&[usize]) {
    }
    fn give_points(&mut self, point_nums:usize, id:&str) {
    }
    fn select_point(&mut self, point_locs:&[Loc], id:&str) {
    }
    fn set_conf(&mut self, id:&str, raw_value:&str) {
    }
    fn reset(&mut self) {
    }
    fn _raii(&mut self) {
        self.shared.send_message_ea(MessageEA::Stop);
    }
    fn _others(&mut self, raw:&str) {
    }
}

impl protocol::Sender for Engine {
    fn on_frame(&mut self) -> protocol::Reply {
        match self.shared.poll_message_ae() {
            MessageAE::MoveLoc(loc) => {
                self.shared.take_message_ae();
                protocol::Reply::MoveLoc(self.last_get_id.clone(), loc)
            }
            MessageAE::MoveSwap => {
                self.shared.take_message_ae();
                protocol::Reply::MoveSwap(self.last_get_id.clone())
            }
            MessageAE::MovePass => {
                self.shared.take_message_ae();
                protocol::Reply::MovePass(self.last_get_id.clone())
            }
            _ => {
                static mut _1:usize = 0;
                if unsafe{_1 == 0} {
                    unsafe{_1 += 1;}
                    protocol::Reply::Conf(String::from("a"), String::from("i|8|32"), String::from("16"), String::from("@vc-depth"))
                } else {
                    protocol::Reply::Nothing
                }
            }
        }
    }
}

fn main() {
    let mut engine = Engine::new();
    if engine.init() {
        protocol::session(ENGINE_NAME, &mut engine);
        engine.raii();
    }
}
